package scheduler

import (
	"context"
	"sync"
	"time"

	"gitee.com/war2001/NiuMaEasyGo/global"
	"gitee.com/war2001/NiuMaEasyGo/service"
	"github.com/robfig/cron/v3"
	"go.uber.org/zap"
)

// Task 定时任务接口
type Task interface {
	Name() string                  // 任务名称
	Run(ctx context.Context) error // 执行任务
}

// TaskFunc 任务函数类型
type TaskFunc func(ctx context.Context) error

// SimpleTask 简单任务实现
type SimpleTask struct {
	name     string
	function TaskFunc
}

// Name 获取任务名称
func (t *SimpleTask) Name() string {
	return t.name
}

// Run 执行任务
func (t *SimpleTask) Run(ctx context.Context) error {
	return t.function(ctx)
}

// NewSimpleTask 创建简单任务
func NewSimpleTask(name string, fn TaskFunc) *SimpleTask {
	return &SimpleTask{
		name:     name,
		function: fn,
	}
}

// Scheduler 调度器
type Scheduler struct {
	cron     *cron.Cron
	tasks    map[string]cron.EntryID
	mutex    sync.RWMutex
	ctx      context.Context
	cancel   context.CancelFunc
	wg       sync.WaitGroup
	timezone *time.Location
	running  bool
}

// Config 调度器配置
type Config struct {
	Timezone string         // 时区
	Location *time.Location // 时区位置
}

// NewScheduler 创建调度器
func NewScheduler(config *Config) (*Scheduler, error) {
	// 设置时区
	location := time.Local
	if config.Location != nil {
		location = config.Location
	} else if config.Timezone != "" {
		var err error
		location, err = time.LoadLocation(config.Timezone)
		if err != nil {
			return nil, err
		}
	}

	// 创建上下文
	ctx, cancel := context.WithCancel(context.Background())

	// 创建调度器
	scheduler := &Scheduler{
		cron:     cron.New(cron.WithLocation(location), cron.WithSeconds()),
		tasks:    make(map[string]cron.EntryID),
		ctx:      ctx,
		cancel:   cancel,
		timezone: location,
		running:  false,
	}

	return scheduler, nil
}

// Start 启动调度器
func (s *Scheduler) Start() {
	s.mutex.Lock()
	defer s.mutex.Unlock()

	if !s.running {
		s.cron.Start()
		s.running = true
		zap.L().Info("调度器已启动")
	}
}

// Stop 停止调度器
func (s *Scheduler) Stop() {
	s.mutex.Lock()
	defer s.mutex.Unlock()

	if s.running {
		s.cron.Stop()
		s.cancel()
		s.wg.Wait()
		s.running = false
		zap.L().Info("调度器已停止")
	}
}

// AddTask 添加定时任务
func (s *Scheduler) AddTask(spec string, task Task) error {
	s.mutex.Lock()
	defer s.mutex.Unlock()

	// 检查任务是否已存在
	if _, exists := s.tasks[task.Name()]; exists {
		return nil // 任务已存在，不重复添加
	}

	// 包装任务执行函数
	wrapper := func() {
		s.wg.Add(1)
		defer s.wg.Done()

		// 创建任务上下文
		taskCtx, taskCancel := context.WithCancel(s.ctx)
		defer taskCancel()

		// 记录开始时间
		startTime := time.Now()
		zap.L().Info("任务开始执行", zap.String("task", task.Name()), zap.Time("start_time", startTime))

		// 执行任务
		err := task.Run(taskCtx)

		// 记录结束时间和执行结果
		endTime := time.Now()
		duration := endTime.Sub(startTime)
		if err != nil {
			zap.L().Error("任务执行失败",
				zap.String("task", task.Name()),
				zap.Error(err),
				zap.Duration("duration", duration),
			)
		} else {
			zap.L().Info("任务执行成功",
				zap.String("task", task.Name()),
				zap.Duration("duration", duration),
			)
		}
	}

	// 添加到cron
	entryID, err := s.cron.AddFunc(spec, wrapper)
	if err != nil {
		return err
	}

	// 记录任务
	s.tasks[task.Name()] = entryID
	zap.L().Info("任务已添加", zap.String("task", task.Name()), zap.String("spec", spec))

	return nil
}

// RemoveTask 移除定时任务
func (s *Scheduler) RemoveTask(name string) {
	s.mutex.Lock()
	defer s.mutex.Unlock()

	if entryID, exists := s.tasks[name]; exists {
		s.cron.Remove(entryID)
		delete(s.tasks, name)
		zap.L().Info("任务已移除", zap.String("task", name))
	}
}

// ListTasks 列出所有定时任务
func (s *Scheduler) ListTasks() []string {
	s.mutex.RLock()
	defer s.mutex.RUnlock()

	tasks := make([]string, 0, len(s.tasks))
	for name := range s.tasks {
		tasks = append(tasks, name)
	}
	return tasks
}

// GetTaskCount 获取任务数量
func (s *Scheduler) GetTaskCount() int {
	s.mutex.RLock()
	defer s.mutex.RUnlock()
	return len(s.tasks)
}

// IsRunning 检查调度器是否运行中
func (s *Scheduler) IsRunning() bool {
	s.mutex.RLock()
	defer s.mutex.RUnlock()
	return s.running
}

// GetTaskEntry 获取任务条目
func (s *Scheduler) GetTaskEntry(name string) *cron.Entry {
	s.mutex.RLock()
	defer s.mutex.RUnlock()

	if entryID, exists := s.tasks[name]; exists {
		entry := s.cron.Entry(entryID)
		return &entry
	}
	return nil
}

// RunTask 立即运行指定任务
func (s *Scheduler) RunTask(name string) error {
	s.mutex.RLock()
	defer s.mutex.RUnlock()

	if entryID, exists := s.tasks[name]; exists {
		entry := s.cron.Entry(entryID)
		if entry.Job != nil {
			go entry.Job.Run()
			zap.L().Info("手动触发任务执行", zap.String("task", name))
			return nil
		}
	}
	return nil
}

// LoginLogCleanupTask 登录日志清理任务
func LoginLogCleanupTask(ctx context.Context) error {
	// 如果服务不可用，则跳过
	if global.Services == nil {
		zap.L().Warn("服务不可用，跳过登录日志清理")
		return nil
	}

	// 尝试转换为服务类型
	if services, ok := global.Services.(*service.Services); ok && services.LoginLog != nil {
		// 默认清理30天前的登录日志
		days := 30
		if global.Config != nil && global.Config.App.LogRetentionDays > 0 {
			days = global.Config.App.LogRetentionDays
		}

		// 执行清理
		err := services.LoginLog.ClearLoginLogs(days)
		if err != nil {
			zap.L().Error("清理登录日志失败", zap.Error(err))
			return err
		}

		zap.L().Info("清理登录日志成功", zap.Int("days", days))
		return nil
	}

	zap.L().Warn("登录日志服务不可用，跳过清理")
	return nil
}
